using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Net;
using System.Web.Caching;
using System.Web;
using System.Diagnostics;

using Microsoft.CommerceServer.Catalog;



namespace CatalogManagerDAL
{
    public class ListEntities
    {
        private CatalogServiceAgent CatalogWebServiceClient = null;
        private CatalogContext CommerceCtx = null;

        #region Cached properties

        /// <summary>
        /// Cached property that holds all ProductDefinitions
        /// </summary>
        private DataTable AllProductDefinitions
        {
            get
            {
                DataSet m_AllProductDefinitions = null;
                if (CatalogCache.catalogCache[Constants.AllProductDefinitionsKey] != null)
                {
                    m_AllProductDefinitions = (DataSet)CatalogCache.catalogCache[Constants.AllProductDefinitionsKey];
                }
                else
                {
                    // fetch only productDefinitions. (0 for ProductDef, 1 for CategoryDef)
                    string SearchClause = "DefinitionType=0";
                    m_AllProductDefinitions = CommerceCtx.GetDefinitions(SearchClause);

                    CatalogCache.catalogCache.Insert(Constants.AllProductDefinitionsKey, m_AllProductDefinitions);
                }

                // dataset is ready, but we want to return dataTable not dataset
                DataTable m_AllProductDefinitionsTable = null;
                if (m_AllProductDefinitions.Tables.Count > 0)
                {
                    m_AllProductDefinitionsTable = m_AllProductDefinitions.Tables[0];
                }

                return m_AllProductDefinitionsTable;
            }
        }

        /// <summary>
        /// Cached property that holds all ProductDefinitionProperties
        /// </summary>
        private DataTable AllProductDefinitionProperties
        {
            get
            {
                DataTable m_AllProductDefinitionPropertiesTable = null;
                DataSet m_ProductDefinitionProperties = null;

                if (CatalogCache.catalogCache[Constants.AllProductDefinitionPropertiesKey] != null)
                {
                    m_ProductDefinitionProperties = (DataSet)CatalogCache.catalogCache[Constants.AllProductDefinitionPropertiesKey];
                }
                else
                {
                    m_ProductDefinitionProperties = CommerceCtx.GetDefinitionProperties(
                        CatalogDefinitionType.ProductDefinition
                    );
                    CatalogCache.catalogCache.Insert(Constants.AllProductDefinitionPropertiesKey, m_ProductDefinitionProperties);
                }

                // dataset is ready, but we want to return dataTable not dataset
                if (m_ProductDefinitionProperties.Tables.Count > 0)
                {
                    m_AllProductDefinitionPropertiesTable = m_ProductDefinitionProperties.Tables[0];
                    m_AllProductDefinitionPropertiesTable.DefaultView.Sort = "PropertyName";
                    m_AllProductDefinitionPropertiesTable = m_AllProductDefinitionPropertiesTable.DefaultView.ToTable();
                }
                return m_AllProductDefinitionPropertiesTable;
            }
        }

        /// <summary>
        /// Cached property that holds all property attributes. Such as required, dataType, displayName, ... etc
        /// </summary>
        private DataTable AllPropertyAttributes
        {
            get
            {
                DataSet m_AllPropertyAttributes = null;
                if (CatalogCache.catalogCache[Constants.AllPropertyAttributesKey] != null)
                {
                    m_AllPropertyAttributes = (DataSet)CatalogCache.catalogCache[Constants.AllPropertyAttributesKey];
                }
                else
                {
                    m_AllPropertyAttributes = CommerceCtx.GetProperties("");
                    CatalogCache.catalogCache.Insert(Constants.AllPropertyAttributesKey, m_AllPropertyAttributes);
                }

                // dataset is ready, but we want to return dataTable not dataset
                DataTable m_AllPropertyAttributesTable = null;
                if (m_AllPropertyAttributes.Tables.Count > 0)
                {
                    m_AllPropertyAttributesTable = m_AllPropertyAttributes.Tables[0];
                }

                return m_AllPropertyAttributesTable;
            }
        }

        /// <summary>
        /// Cached property that holds all CategoryDefinitionProperties
        /// </summary>
        private DataTable AllCategoryDefinitionProperties
        {
            get
            {
                DataTable m_AllCategoryDefinitionPropertiesTable = null;
                DataSet m_CategoryDefinitionProperties = null;

                if (CatalogCache.catalogCache[Constants.AllCategoryDefinitionPropertiesKey] != null)
                {
                    m_CategoryDefinitionProperties = (DataSet)CatalogCache.catalogCache[Constants.AllCategoryDefinitionPropertiesKey];
                }
                else
                {
                    m_CategoryDefinitionProperties = CommerceCtx.GetDefinitionProperties(
                        CatalogDefinitionType.CategoryDefinition
                    );
                    CatalogCache.catalogCache.Insert(Constants.AllCategoryDefinitionPropertiesKey, m_CategoryDefinitionProperties);
                }

                // dataset is ready, but we want to return dataTable not dataset
                if (m_CategoryDefinitionProperties.Tables.Count > 0)
                {
                    m_AllCategoryDefinitionPropertiesTable = m_CategoryDefinitionProperties.Tables[0];
                    m_AllCategoryDefinitionPropertiesTable.DefaultView.Sort = "PropertyName";
                    m_AllCategoryDefinitionPropertiesTable = m_AllCategoryDefinitionPropertiesTable.DefaultView.ToTable();
                }
                return m_AllCategoryDefinitionPropertiesTable;
            }
        }

        private Dictionary<string, DataColumnCollection> m_AllProductDefinitionColumns = new Dictionary<string, DataColumnCollection>();

        #endregion

        public ListEntities()
        {
            this.CatalogWebServiceClient = DataHelper.InitServiceAgent();
            CommerceCtx = DataHelper.InitContext();
        }

        public DataTable ListSingleCategoryDefinitionsProperties(string CategoryDefinitionName)
        {
            // Retrieves ProductDefinitionProps from db or gets it from cache: this.AllProductDefinitionProperties
            DataTable FilteredTable = null;

            if (CategoryDefinitionName.Length == 0) FilteredTable = this.AllCategoryDefinitionProperties;
            else
            {
                FilteredTable = DataHelper.FilterTable(
                     this.AllCategoryDefinitionProperties,
                     String.Format("DefinitionName='{0}'", CategoryDefinitionName)
                 );
            }

            return FilteredTable;
        }

        public DataTable ListSingleProductDefinitionsProperties(string ProductDefinitionName)
        {
            // Retrieves ProductDefinitionProps from db or gets it from cache: this.AllProductDefinitionProperties
            DataTable FilteredTable = null;

            if (ProductDefinitionName.Length == 0) FilteredTable = this.AllProductDefinitionProperties;
            else
            {
                FilteredTable = DataHelper.FilterTable(
                     this.AllProductDefinitionProperties,
                     String.Format("DefinitionName='{0}'", ProductDefinitionName)
                 );
            }

            return FilteredTable;
        }

        public DataTable ListSingleProductDefinitionsProperties_AllProperties(string ProductDefinitionName)
        {
            DataTable FilteredTable = null;

            if (ProductDefinitionName.Length == 0) FilteredTable = this.AllProductDefinitionProperties;
            else
            {
                FilteredTable = DataHelper.FilterTable(
                     this.AllProductDefinitionProperties,
                     String.Format("DefinitionName='{0}'", ProductDefinitionName)
                 );
            }

            return FilteredTable;
        }

        public DataSet ListProductDefinitions()
        {
            DataSet dset = new DataSet();
            dset.Tables.Add(this.AllProductDefinitions.Copy());
            return dset;
        }

        public DataTable GetAllAssignedProperties()
        {
            return DataHelper.FilterTable(
                this.AllPropertyAttributes, "AssignAll=1"
            );
        }

        public DataRow GetProductDefinitionPropertyAttributes(string PropertyFilter)
        {
            DataRow PropertyAttributes = null;

            DataTable FilteredSinglePropertyAttributes = DataHelper.FilterTable(
                this.AllPropertyAttributes, PropertyFilter
            );

            if (FilteredSinglePropertyAttributes.Rows.Count == 1)
            {
                PropertyAttributes = FilteredSinglePropertyAttributes.Rows[0];
            }

            return PropertyAttributes;
        }

        public DataRow GetCategoryDefinitionPropertyAttributes(string PropertyFilter)
        {
            DataRow PropertyAttributes = null;

            DataTable FilteredSinglePropertyAttributes = DataHelper.FilterTable(
                this.AllPropertyAttributes, PropertyFilter
            );

            if (FilteredSinglePropertyAttributes.Rows.Count == 1)
            {
                PropertyAttributes = FilteredSinglePropertyAttributes.Rows[0];
            }

            return PropertyAttributes;
        }

        public DataTable ListCatalogs()
        {
            return ListCatalogs(" CatalogType IN (N'CatalogType_A', N'CatalogType_B') ");
        }

        public DataTable ListCatalogs(string SqlWhereClause)
        {
            Microsoft.CommerceServer.Catalog.CatalogSearchOptions cso = new Microsoft.CommerceServer.Catalog.CatalogSearchOptions();
            cso.StartingRecord = 1;
            cso.RecordsToRetrieve = 500;
            cso.PropertiesToReturn = "*"; 
            cso.SortProperty = "DisplayName_en-US";

            Microsoft.CommerceServer.Catalog.XmlData.CatalogSearchParameters catalogSearchParameters = new Microsoft.CommerceServer.Catalog.XmlData.CatalogSearchParameters();
            // catalogSearchParameters.SqlWhereClause = SqlWhereClause;
            
            CatalogsDataSet Catalogs = CommerceCtx.GetCatalogs(
                // "IsVirtualCatalog = 1 AND CatalogType IN (N'StarterSite', N'Special') "
                "" // SqlWhereClause
            );

            DataTable CatalogsTable = null;
            if (Catalogs.Tables.Count>0) CatalogsTable = Catalogs.Tables[0];

            return CatalogsTable;
        }

        private DataTable ListCategories(string CatalogName)
        {
            DataTable CategoriesTable = null;
            if (CatalogName.Length == 0) return CategoriesTable;

            Category catalogCategory = CommerceCtx.GetRootCategory(CatalogName);
            CategoryCollection categories = catalogCategory.ChildCategories;                       
            if (categories.DataSet.Tables.Count > 0) CategoriesTable = categories.DataSet.Tables[0];

            return CategoriesTable;
        }

        public DataTable ListCategories(string CatalogName, string CategoryName)
        {
            DataTable CategoriesTable = null;
            if (    String.IsNullOrEmpty(CategoryName)
                && !String.IsNullOrEmpty(CatalogName)
                ) 
            {
                CategoriesTable = ListCategories(CatalogName);
            }
            else if(   !String.IsNullOrEmpty(CategoryName)
                    && !String.IsNullOrEmpty(CatalogName)
                ) 
            {
                CategoriesTable = ListCategoriesOfCategory(CatalogName, CategoryName);
            }
            return CategoriesTable;
        }

        private DataTable ListCategoriesOfCategory(string CatalogName, string CategoryName)
        {
            DataTable CategoriesTable = null;
            if (String.IsNullOrEmpty(CatalogName) || String.IsNullOrEmpty(CategoryName)) 
            {
                return CategoriesTable;
            }

            Category catalogCategory = CommerceCtx.GetCategory(CatalogName, CategoryName);
            CategoryCollection categories = catalogCategory.ChildCategories;
            if (categories.DataSet.Tables.Count > 0) CategoriesTable = categories.DataSet.Tables[0];

            return CategoriesTable;
        }

        internal void AddAttribute(string PropertyName, ref DataTable DefinitionProperties)
        {
            DataRow PropertyTypeRow = GetProductDefinitionPropertyAttributes(
                String.Format("PropertyName='{0}'", PropertyName)
            );
            
            DataRow dr = DefinitionProperties.NewRow();

            dr[Constants.DefinitionProperties_DefinitionId] = 0;
            dr[Constants.DefinitionProperties_PropertyType] = 0;
            dr[Constants.DefinitionProperties_DefinitionName] = "CUSTOM_ADDED";
            dr[Constants.DefinitionProperties_PropertyName] = PropertyName;
            dr[Constants.DefinitionProperties_DefinitionType] = 0;
            dr[Constants.DefinitionProperties_PropertyDataType] = Convert.ToInt32( PropertyTypeRow["DataType"] );
            dr[Constants.DefinitionProperties_PropertyDisplayName] = Convert.ToString(PropertyTypeRow["DisplayName_en-US"]);
            dr[Constants.DefinitionProperties_IsRequired] = Convert.ToBoolean(PropertyTypeRow["IsRequired"]);

            DefinitionProperties.Rows.Add(dr);
        }

        internal void AddAttribute(string PropertyName, ref DataTable DefinitionProperties, bool IsRequired)
        {
            AddAttribute(PropertyName, ref DefinitionProperties);
            DefinitionProperties.PrimaryKey = new DataColumn[] {
                DefinitionProperties.Columns[Constants.DefinitionProperties_PropertyName]
            };
            DataRow dr = DefinitionProperties.Rows.Find(
                new object[] { 
                    PropertyName
                }
            );
            if (null != dr)
            {
                dr[Constants.DefinitionProperties_IsRequired] = IsRequired;
            }
        }

        public DataTable ListProducts(string CatalogName, string CategoryName)
        {
            DataTable productsTable = null;
            Category category = CommerceCtx.GetCategory(CatalogName, CategoryName);
            CatalogItemsDataSet catalogItems = category.ChildProducts.DataSet;
            if (catalogItems.Tables.Count>0)
            {
                productsTable = catalogItems.Tables[0];
            }
            return productsTable;
        }
    }
}
